/*
 *
 *
Copyright (c) 1998-2001 Aristar, Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. The end-user documentation included with the redistribution, if any,
must include the following acknowledgment:

"This product includes software developed by Aristar, Inc. (http://www.aristar.com/)."

Alternately, this acknowledgment may appear in the software itself, if and
wherever such third-party acknowledgments normally appear.

4. The names "Dialect" and "Aristar, Inc." must not be used to endorse or
promote products derived from this software without prior written permission.
For written permission, please contact info@aristar.com.

5. Products derived from this software may not be called "Dialect", nor may
"Dialect" appear in their name, without prior written permission of Aristar, Inc.

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
ARISTAR, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software consists of voluntary contributions made by many individuals
on behalf of Aristar, Inc.  For more information on Aristar, Inc.,
please see <http://www.aristar.com/>.

Portions of this software are based upon software freely available and
written by individuals not associated with Aristar, Inc.  Copyrights are
maintained in the relevant source code files.
 *
 *
 */

#ifndef CIMPLEMENTER_H__
#define CIMPLEMENTER_H__


#include "DConfigGlobals.h"
#include "CByteCode.h"
#include "CValue.h"

//=======================================================

class CInterpreter;

class CImplementer {
protected:
	friend VALUE;
	CImplementer();		// Use VALUE to construct these since it does reference counting
	int IncRefCount();
	int DecRefCount();
	void SetRefCount(int refCount);
#ifdef __THREADS__
	MUTEX_T m_RefMutex;
#endif

public:
	virtual ~CImplementer();
	int m_RefCount;		// For grabage collection purposes (manipulated by VALUE class)
	virtual void SerializeOut(CFile* outFile);

	void ThrowError(LPCTSTR what) const;

	virtual VALUE* FindValuePtr(const VALUE& key, bool bCreateOK);

	virtual bool __boolean__();
	virtual TString __unparse__();
	virtual TString __string__();
	virtual void __set__(const VALUE& indexer, const VALUE& arg);
	virtual VALUE __get__(const VALUE& arg);
	virtual VALUE operator[] (const VALUE& arg);
	virtual void __findnext__(FindNextInfo& fni, VALUE& value);
	virtual void __findnext__(FindNextInfo& fni, VALUE& key, VALUE& value);
	virtual int __length__() const;
	virtual void __resize__(int newLength, VALUE init);
	virtual VALUE __clone__();
	virtual VALUE __deepclone__();
};


//////////////////////////////////////////////////////////////////
// DO NOT CHANGE THE FOLLOWING DEFINITIONS!!!!!!!!!!!!!!!!!!!!!!!!
// SERIALIZED CHUNKS RELY ON THESE TO UNSERIALIZE CORRECTLY!!!!!!!
// If you need to add more types/encodings, add them to the end

// Chunk data index size/types
#define it_undefined	0
#define it_i1			1	// char
#define it_i2			2	// short
#define it_i4			3	// int
#define it_i8			4	// for when we move to 64-bit CPUs
#define it_ui1			5	// unsigned char
#define it_ui2			6	// unsigned short
#define it_ui3			7	// unsigned 3-byte int (maybe for 24-bit color bitmaps)
#define it_ui4			8	// unsigned int
#define it_ui8			9	// for when we move to 64-bit CPUs
#define it_f4			10	// 32bit float
#define it_f8			11	// 64bit float
// Chunk encoding types when stringified
#define enc_undefined	0
#define enc_base64		1	// MIME compatible base64
#define enc_hex			2	// Standard hex
#define enc_binary		3	// All ones and zeros (duh)
#define enc_ascii		4	// Standard 8 bit ASCII char values

class CChunkImpl : public CImplementer {
protected:
	friend VALUE;
	CChunkImpl(int length, const U8* data = NULL, int encoding = enc_base64,
		int itype = it_ui1);
	CChunkImpl(TString text, int encoding, int itype = it_ui1);
public:
	~CChunkImpl();
protected:
	int m_Length;
	U8* m_Data;
public:
	int m_IndexType;
	int m_EncodingType;
	int m_DimensionCount;
	int *m_Dimensions;
	static U8* SerializeIn(U8* inBuffer, CImplementer** result);
	void SerializeOut(CFile* outFile);
	int __length__() const;
	void __resize__(int newLength, VALUE init);
	TString __unparse__();
	TString __string__();
	VALUE __clone__();
	VALUE __deepclone__();
	VALUE __get__(const VALUE& arg);
	void __set__(const VALUE& indexer, const VALUE& arg);
	void __findnext__(FindNextInfo& fni, VALUE& key);
	U8* GetData();
};

class CArrayImpl : public CImplementer {
protected:
	friend VALUE;
	CArrayImpl(int length, const VALUE initEntries[] = NULL);	// init with array
public:
	~CArrayImpl();
	int m_Length;
	VALUE* m_Values;

	static U8* SerializeIn(U8* inBuffer, CImplementer** result);
	void SerializeOut(CFile* outFile);

	VALUE* FindValuePtr(const VALUE& key, bool bCreateOK);
	bool __boolean__();
	int __length__() const;
	void __resize__(int newLength, VALUE init);
	TString __unparse__();
	VALUE Left(int count);
	VALUE Right(int count);

	void __findnext__(FindNextInfo& fni, VALUE& value);

	TString __string__();
	VALUE __clone__();
	VALUE __deepclone__();

	VALUE __get__(const VALUE& arg);
	void __set__(const VALUE& indexer, const VALUE& arg);
	VALUE operator[] (const VALUE& arg);
};

//==============================================================

class CFrameImpl : public CImplementer {
protected:
	friend CInterpreter;
	friend VALUE;
	CFrameImpl(int tableSize = 97);
public:
	~CFrameImpl();

	static U8* SerializeIn(U8* inBuffer, CImplementer** result);
	void SerializeOut(CFile* outFile);

	VALUE* FindValuePtr(const VALUE& key, bool bCreateOK);
	VALUE* FindValuePtr(TString& key, bool bCreateOK);
	void Empty();
	TString __unparse__();
	TString __string__();
	int __length__() const;
	bool __boolean__();
	VALUE __clone__();
	VALUE __deepclone__();

	void __set__(const VALUE& indexer, const VALUE& arg);
	VALUE __get__(const VALUE& arg);
	VALUE operator[] (const VALUE& arg);

	void __findnext__(FindNextInfo& fni, VALUE& key, VALUE& value);

	struct CFrameLinkNode {
		CFrameLinkNode(TString key, VALUE value, CFrameLinkNode* next);
		~CFrameLinkNode();
		TString m_Key;
		VALUE m_Value;
		CFrameLinkNode* m_Next;
	};

	CFrameLinkNode* GetNodePtr(const TString& key);
	CFrameImpl::CFrameLinkNode* Add(const TString& key, VALUE value);
	bool Remove(const TString& key);

protected:
	int m_NumberOfEntries;
	int HashFunction(const TString& key) const;
	int m_TableSize;
	CFrameLinkNode** m_HashTable;
};

class CSymbolImpl : public CImplementer {
protected:
	friend VALUE;
	CSymbolImpl(TString symName);
public:
	~CSymbolImpl();
	bool __boolean__();
	static U8* SerializeIn(U8* inBuffer, CImplementer** result);
	void SerializeOut(CFile* outFile);
	TString __unparse__();
	TString __string__();
	VALUE __clone__();
	VALUE __deepclone__();

	TString m_SymbolName;
};

//=========================================================

class CClassImpl : public CImplementer {
protected:
	friend VALUE;
	CClassImpl(VALUE base, TString className);
public:
	~CClassImpl();

	VALUE* FindValuePtr(const VALUE& key, bool bCreateOK);
	virtual VALUE* FindValuePtrNoSelf(TString& key);
	virtual void __del__(VALUE* self);
	VALUE operator[] (const VALUE& arg);
	VALUE __get__(const VALUE& arg);
	void __set__(const VALUE& indexer, const VALUE& arg);
	bool IsA(TString className);
	TString __unparse__();
	TString __string__();

	TString m_ClassName;		// Name used in class declaration
	VALUE m_BaseClass;			// stClass
	VALUE m_MemberSymTab;		// stFrame
	bool m_bIsClassInstance;	// Derived class, CClassInstanceImpl, sets this to true
};

class CClassInstImpl : public CClassImpl {
protected:
	friend VALUE;
	CClassInstImpl(VALUE base, CInterpreter* pCreater);
public:
	~CClassInstImpl();

	VALUE* FindValuePtr(const VALUE& key, bool bCreateOK);
	VALUE* FindValuePtrNoSelf(TString& key);

	VALUE operator[] (const VALUE& arg);
	VALUE __get__(const VALUE& arg);
	void __set__(const VALUE& indexer, const VALUE& arg);
	TString __unparse__();
	TString __string__();

	VALUE m_SelfSymTab;			// stFrame
};

//==============================================================

class CFunctionImpl : public CImplementer {
protected:
	friend VALUE;
	CFunctionImpl();
	CFunctionImpl(CByteCode* code, TString paramList[], int paramCount);
	CFunctionImpl(VALUE (*lpCoreFunc)(VALUE* self, int argCount, VALUE argVals[],
		CInterpreter* pInterp), TString moduleName);
public:
	~CFunctionImpl();
	bool ExecuteCoreFunc(VALUE& result, int argCount, VALUE argVals[], CInterpreter* pInterp);
	TString __unparse__();
	TString __string__();
	VALUE __clone__();
	VALUE __deepclone__();

	static U8* SerializeIn(U8* inBuffer, CImplementer** result);
	void SerializeOut(CFile* outFile);

	union {
		// Function is interpreted code
		CByteCode* m_CodeStream;
		// Function is C code
		VALUE (*m_lpCoreFunc)(VALUE* self, int argCount, VALUE argVals[], CInterpreter* pInterp);
	};
	int m_ParamCount;
	TString* m_ParamList;
	CClassImpl* m_pClassImpl;	// To add to call stack when executing this func
	CClassInstImpl* m_pClassInstImpl;
	int m_EndLine;	// The module line number where the tokEndFunc was found (-1 for core, or unkown)
	TString m_ModuleName;	// Explicitly set in core funcs, otherwise grabbed from code stream
};

class CPropertyImpl : public CImplementer {
protected:
	friend VALUE;
	CPropertyImpl();
	CPropertyImpl(VALUE readFunc, VALUE writeFunc, VALUE vInitial);
public:
	~CPropertyImpl();
	TString __unparse__();
	VALUE m_vPropValue;
	VALUE m_ReadFunc;
	VALUE m_WriteFunc;
};

//==============================================================
#endif	// CIMPLEMENTER_H__